{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Offline Pre-processing Tutorial"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This is a short demo that shows how to use `BatchGenerator` to process a dataset offline, i.e. to perform some transformations on all images (and maybe ground truth images, too) of some dataset(s) and then save the results to some target directory. In doing so, the generator reproduces the same directory hierarchy of the source directory in the target directory.\n",
    "\n",
    "If ground truth data is given, it is being processed consistently with the respective images, of course.\n",
    "\n",
    "The example used here is the Cityscapes dataset:\n",
    "https://www.cityscapes-dataset.com/"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from batch_generator import BatchGenerator\n",
    "from cityscapesscripts.helpers.labels import IDS_TO_TRAINIDS_ARRAY"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. Set source and destination paths\n",
    "\n",
    "1. Set the paths to an arbitrary number of source datasets that you wish to process.\n",
    "2. Set an export directory, i.e. the directory into which you want to export the processed data.\n",
    "3. Set the root directory of the datasets to be processed. The generator will reproduce the directory hierarchy that it finds inside this root directory in the export directory."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# The directories that contain the train, val, and test images\n",
    "train_images = '../../datasets/Cityscapes/leftImg8bit/train/'\n",
    "train_extra_images = '../../datasets/Cityscapes/leftImg8bit/train_extra/'\n",
    "val_images = '../../datasets/Cityscapes/leftImg8bit/val/'\n",
    "test_images = '../../datasets/Cityscapes/leftImg8bit/test/'\n",
    "\n",
    "# The directories that contain the train and val ground truth images\n",
    "train_gt = '../../datasets/Cityscapes/gtFine/train/'\n",
    "train_extra_gt = '../../datasets/Cityscapes/gtCoarse/train_extra/'\n",
    "val_gt = '../../datasets/Cityscapes/gtFine/val/'\n",
    "\n",
    "# Define which of the above to pass to the `BatchGenerator` constructor.\n",
    "image_dirs = [train_images, val_images]\n",
    "ground_truth_dirs = [train_gt, val_gt]\n",
    "\n",
    "export_dir = '../../datasets/Cityscapes_small/' # The directory into which you want to export the processed images\n",
    "root_dir = '../../datasets/Cityscapes/' # The root directory of the dataset."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. Instantiate a BatchGenerator\n",
    "\n",
    "Create a `BatchGenerator` instance and pass it a list of directories containing the images (and maybe ground truth images) that you wish to process."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Total number of files in all datasets:  500\n"
     ]
    }
   ],
   "source": [
    "offline_processor = BatchGenerator(image_dirs=image_dirs,\n",
    "                                   image_file_extension='png',\n",
    "                                   ground_truth_dirs=ground_truth_dirs,\n",
    "                                   image_name_split_separator='leftImg8bit',\n",
    "                                   ground_truth_suffix='gtFine_labelIds',\n",
    "                                   check_existence=True,\n",
    "                                   root_dir=root_dir,\n",
    "                                   export_dir=export_dir)\n",
    "\n",
    "num_files = offline_processor.get_num_files()\n",
    "print(\"Total number of files in all datasets: \", num_files)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. Set the processing parameters and start the processing\n",
    "\n",
    "Simply call `process_all()` on the `BatchGenerator` instance with the desired parameters.\n",
    "\n",
    "In this example I want to do two things with the data:\n",
    "\n",
    "1. The segmentation class IDs in the Cityscapes ground truth images range from 0 to 33 and contain a whole bunch of irrelevant classes that are being ignored in the evaluation. I am only interested in learning the 19 classes that count for evaluation. I will therefore remap the IDs of the relevant classes to IDs 1 through 20 and I will map all irrelevant classes to one collective background class ID, namely 0. I simply pass the generator an integer array that represents the map. I could also pass a map in the form of a dictionary instead, but that would slow down the processing. Once I'm done training my model, I can revert this mapping back to the original class IDs the same way.\n",
    "\n",
    "2. The images in the Cityscapes datasets have a size of `(1024, 2048)`. I wish I could just train on these full-size images, but that's too large for my GPU. I will therefore downsize the images by a factor of 16 to `(256, 512)`.\n",
    "\n",
    "Take a look at the documentation for more details on the above transformations and to learn about the other transformations available in `BatchGenerator`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing images: 100%|██████████| 500/500 [01:21<00:00,  6.15it/s]\n"
     ]
    }
   ],
   "source": [
    "offline_processor.process_all(convert_colors_to_ids=False,\n",
    "                              convert_ids_to_ids=IDS_TO_TRAINIDS_ARRAY, # <-- Convert the class IDs to different ones.\n",
    "                              convert_to_one_hot=False,\n",
    "                              void_class_id=None,\n",
    "                              random_crop=False,\n",
    "                              crop=False,\n",
    "                              resize=(256, 512), # <-- Resize the images.\n",
    "                              brightness=False,\n",
    "                              flip=False,\n",
    "                              translate=False,\n",
    "                              scale=False,\n",
    "                              gray=False,\n",
    "                              to_disk=True) # <-- Save the processed images to disk."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
